summaryrefslogtreecommitdiffstats
path: root/sys/boot
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot')
-rw-r--r--sys/boot/arm/uboot/Makefile2
-rw-r--r--sys/boot/common/bootstrap.h2
-rw-r--r--sys/boot/common/module.c13
-rw-r--r--sys/boot/common/ufsread.c9
-rw-r--r--sys/boot/efi/Makefile8
-rw-r--r--sys/boot/efi/boot1/Makefile33
-rw-r--r--sys/boot/efi/boot1/boot1.c403
-rw-r--r--sys/boot/efi/boot1/boot_module.h110
-rw-r--r--sys/boot/efi/boot1/ufs_module.c254
-rw-r--r--sys/boot/efi/boot1/zfs_module.c199
-rw-r--r--sys/boot/efi/fdt/Makefile2
-rw-r--r--sys/boot/efi/include/efilib.h4
-rw-r--r--sys/boot/efi/libefi/Makefile1
-rw-r--r--sys/boot/efi/libefi/handles.c24
-rw-r--r--sys/boot/efi/loader/Makefile20
-rw-r--r--sys/boot/efi/loader/conf.c9
-rw-r--r--sys/boot/efi/loader/devicename.c57
-rw-r--r--sys/boot/efi/loader/main.c169
-rw-r--r--sys/boot/fdt/fdt_loader_cmd.c2
-rw-r--r--sys/boot/i386/loader/main.c29
-rw-r--r--sys/boot/userboot/test/test.c12
-rw-r--r--sys/boot/userboot/userboot/main.c27
-rw-r--r--sys/boot/zfs/libzfs.h1
-rw-r--r--sys/boot/zfs/zfs.c33
-rw-r--r--sys/boot/zfs/zfsimpl.c8
25 files changed, 1127 insertions, 304 deletions
diff --git a/sys/boot/arm/uboot/Makefile b/sys/boot/arm/uboot/Makefile
index a5f7096..7f0fd2e 100644
--- a/sys/boot/arm/uboot/Makefile
+++ b/sys/boot/arm/uboot/Makefile
@@ -8,8 +8,6 @@ NEWVERSWHAT= "U-Boot loader" ${MACHINE_ARCH}
BINDIR?= /boot
INSTALLFLAGS= -b
WARNS?= 1
-CWARNFLAGS.gcc+= -Wno-int-to-pointer-cast
-
# Address at which ubldr will be loaded.
# This varies for different boards and SOCs.
UBLDR_LOADADDR?= 0x1000000
diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h
index 78d742d..7efc2c2 100644
--- a/sys/boot/common/bootstrap.h
+++ b/sys/boot/common/bootstrap.h
@@ -237,7 +237,7 @@ void unload(void);
struct preloaded_file *file_alloc(void);
struct preloaded_file *file_findfile(const char *name, const char *type);
struct file_metadata *file_findmetadata(struct preloaded_file *fp, int type);
-struct preloaded_file *file_loadraw(char *name, char *type, int insert);
+struct preloaded_file *file_loadraw(const char *name, char *type, int insert);
void file_discard(struct preloaded_file *fp);
void file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p);
int file_addmodule(struct preloaded_file *fp, char *modname, int version,
diff --git a/sys/boot/common/module.c b/sys/boot/common/module.c
index d73f1c8..923da5b 100644
--- a/sys/boot/common/module.c
+++ b/sys/boot/common/module.c
@@ -388,14 +388,14 @@ file_load_dependencies(struct preloaded_file *base_file)
}
/*
- * We've been asked to load (name) as (type), so just suck it in,
+ * We've been asked to load (fname) as (type), so just suck it in,
* no arguments or anything.
*/
struct preloaded_file *
-file_loadraw(char *name, char *type, int insert)
+file_loadraw(const char *fname, char *type, int insert)
{
struct preloaded_file *fp;
- char *cp;
+ char *name;
int fd, got;
vm_offset_t laddr;
@@ -406,12 +406,11 @@ file_loadraw(char *name, char *type, int insert)
}
/* locate the file on the load path */
- cp = file_search(name, NULL);
- if (cp == NULL) {
- sprintf(command_errbuf, "can't find '%s'", name);
+ name = file_search(fname, NULL);
+ if (name == NULL) {
+ sprintf(command_errbuf, "can't find '%s'", fname);
return(NULL);
}
- name = cp;
if ((fd = open(name, O_RDONLY)) < 0) {
sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno));
diff --git a/sys/boot/common/ufsread.c b/sys/boot/common/ufsread.c
index acff1e5..08ab697 100644
--- a/sys/boot/common/ufsread.c
+++ b/sys/boot/common/ufsread.c
@@ -187,8 +187,15 @@ fsread(ufs_ino_t inode, void *buf, size_t nbyte)
blkbuf = dmadat->blkbuf;
indbuf = dmadat->indbuf;
- if (!dsk_meta) {
+
+ /*
+ * Force probe if inode is zero to ensure we have a valid fs, otherwise
+ * when probing multiple paritions, reads from subsequent parititions
+ * will incorrectly succeed.
+ */
+ if (!dsk_meta || inode == 0) {
inomap = 0;
+ dsk_meta = 0;
for (n = 0; sblock_try[n] != -1; n++) {
if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
SBLOCKSIZE / DEV_BSIZE))
diff --git a/sys/boot/efi/Makefile b/sys/boot/efi/Makefile
index 57d4e81..94a975a 100644
--- a/sys/boot/efi/Makefile
+++ b/sys/boot/efi/Makefile
@@ -2,7 +2,8 @@
.include <src.opts.mk>
-SUBDIR= libefi
+# In-tree GCC does not support __attribute__((ms_abi)).
+.if ${COMPILER_TYPE} != "gcc"
.if ${MACHINE_CPUARCH} == "aarch64" || ${MACHINE_CPUARCH} == "arm"
.if ${MK_FDT} != "no"
@@ -13,7 +14,10 @@ SUBDIR+= fdt
.if ${MACHINE_CPUARCH} == "aarch64" || \
${MACHINE_CPUARCH} == "amd64" || \
${MACHINE_CPUARCH} == "arm"
-SUBDIR+= loader boot1
+SUBDIR+= libefi loader boot1
.endif
+.endif # ${COMPILER_TYPE} != "gcc"
+
.include <bsd.subdir.mk>
+
diff --git a/sys/boot/efi/boot1/Makefile b/sys/boot/efi/boot1/Makefile
index 9a003ce..7c983e3 100644
--- a/sys/boot/efi/boot1/Makefile
+++ b/sys/boot/efi/boot1/Makefile
@@ -2,10 +2,7 @@
MAN=
-.include <bsd.own.mk>
-
-# In-tree GCC does not support __attribute__((ms_abi)).
-.if ${COMPILER_TYPE} != "gcc"
+.include <src.opts.mk>
MK_SSP= no
@@ -13,14 +10,38 @@ PROG= boot1.sym
INTERNALPROG=
WARNS?= 6
+.if ${MK_ZFS} != "no"
+# Disable warnings that are currently incompatible with the zfs boot code
+CWARNFLAGS.zfs_module.c += -Wno-array-bounds
+CWARNFLAGS.zfs_module.c += -Wno-cast-align
+CWARNFLAGS.zfs_module.c += -Wno-cast-qual
+CWARNFLAGS.zfs_module.c += -Wno-missing-prototypes
+CWARNFLAGS.zfs_module.c += -Wno-sign-compare
+CWARNFLAGS.zfs_module.c += -Wno-unused-parameter
+CWARNFLAGS.zfs_module.c += -Wno-unused-function
+.endif
+
# architecture-specific loader code
-SRCS= boot1.c self_reloc.c start.S
+SRCS= boot1.c self_reloc.c start.S ufs_module.c
+.if ${MK_ZFS} != "no"
+SRCS+= zfs_module.c
+.endif
CFLAGS+= -I.
CFLAGS+= -I${.CURDIR}/../include
CFLAGS+= -I${.CURDIR}/../include/${MACHINE}
CFLAGS+= -I${.CURDIR}/../../../contrib/dev/acpica/include
CFLAGS+= -I${.CURDIR}/../../..
+CFLAGS+= -DEFI_UFS_BOOT
+.ifdef(EFI_DEBUG)
+CFLAGS+= -DEFI_DEBUG
+.endif
+
+.if ${MK_ZFS} != "no"
+CFLAGS+= -I${.CURDIR}/../../zfs/
+CFLAGS+= -I${.CURDIR}/../../../cddl/boot/zfs/
+CFLAGS+= -DEFI_ZFS_BOOT
+.endif
# Always add MI sources and REGULAR efi loader bits
.PATH: ${.CURDIR}/../loader/arch/${MACHINE}
@@ -96,8 +117,6 @@ boot1.efifat: boot1.efi
CLEANFILES= boot1.efi boot1.efifat
-.endif # ${COMPILER_TYPE} != "gcc"
-
.include <bsd.prog.mk>
beforedepend ${OBJS}: machine
diff --git a/sys/boot/efi/boot1/boot1.c b/sys/boot/efi/boot1/boot1.c
index 2b000e0..f046235 100644
--- a/sys/boot/efi/boot1/boot1.c
+++ b/sys/boot/efi/boot1/boot1.c
@@ -5,6 +5,8 @@
* All rights reserved.
* Copyright (c) 2014 Nathan Whitehorn
* All rights reserved.
+ * Copyright (c) 2015 Eric McCorkle
+ * All rights reserved.
*
* Redistribution and use in source and binary forms are freely
* permitted provided that the above copyright notice and this
@@ -21,7 +23,6 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/dirent.h>
#include <machine/elf.h>
#include <machine/stdarg.h>
#include <stand.h>
@@ -29,19 +30,32 @@ __FBSDID("$FreeBSD$");
#include <efi.h>
#include <eficonsctl.h>
+#include "boot_module.h"
+
#define _PATH_LOADER "/boot/loader.efi"
-#define _PATH_KERNEL "/boot/kernel/kernel"
-#define BSIZEMAX 16384
+static const boot_module_t *boot_modules[] =
+{
+#ifdef EFI_ZFS_BOOT
+ &zfs_module,
+#endif
+#ifdef EFI_UFS_BOOT
+ &ufs_module
+#endif
+};
+
+#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*))
+/* The initial number of handles used to query EFI for partitions. */
+#define NUM_HANDLES_INIT 24
-void panic(const char *fmt, ...) __dead2;
void putchar(int c);
EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab);
-static int domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet);
-static void load(const char *fname);
+static void try_load(const boot_module_t* mod);
+static EFI_STATUS probe_handle(EFI_HANDLE h);
-static EFI_SYSTEM_TABLE *systab;
+EFI_SYSTEM_TABLE *systab;
+EFI_BOOT_SERVICES *bs;
static EFI_HANDLE *image;
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
@@ -49,27 +63,92 @@ static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
static EFI_GUID ConsoleControlGUID = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
-static EFI_BLOCK_IO *bootdev;
-static EFI_DEVICE_PATH *bootdevpath;
-static EFI_HANDLE *bootdevhandle;
+/*
+ * Provide Malloc / Free backed by EFIs AllocatePool / FreePool which ensures
+ * memory is correctly aligned avoiding EFI_INVALID_PARAMETER returns from
+ * EFI methods.
+ */
+void *
+Malloc(size_t len, const char *file __unused, int line __unused)
+{
+ void *out;
+
+ if (bs->AllocatePool(EfiLoaderData, len, &out) == EFI_SUCCESS)
+ return (out);
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
+ return (NULL);
+}
+
+void
+Free(void *buf, const char *file __unused, int line __unused)
{
- EFI_HANDLE handles[128];
- EFI_BLOCK_IO *blkio;
- UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
+ (void)bs->FreePool(buf);
+}
+
+/*
+ * This function only returns if it fails to load the kernel. If it
+ * succeeds, it simply boots the kernel.
+ */
+void
+try_load(const boot_module_t *mod)
+{
+ size_t bufsize;
+ void *buf;
+ dev_info_t *dev;
+ EFI_HANDLE loaderhandle;
+ EFI_LOADED_IMAGE *loaded_image;
+ EFI_STATUS status;
+
+ status = mod->load(_PATH_LOADER, &dev, &buf, &bufsize);
+ if (status == EFI_NOT_FOUND)
+ return;
+
+ if (status != EFI_SUCCESS) {
+ printf("%s failed to load %s (%lu)\n", mod->name, _PATH_LOADER,
+ EFI_ERROR_CODE(status));
+ return;
+ }
+
+ if ((status = bs->LoadImage(TRUE, image, dev->devpath, buf, bufsize,
+ &loaderhandle)) != EFI_SUCCESS) {
+ printf("Failed to load image provided by %s, size: %zu, (%lu)\n",
+ mod->name, bufsize, EFI_ERROR_CODE(status));
+ return;
+ }
+
+ if ((status = bs->HandleProtocol(loaderhandle, &LoadedImageGUID,
+ (VOID**)&loaded_image)) != EFI_SUCCESS) {
+ printf("Failed to query LoadedImage provided by %s (%lu)\n",
+ mod->name, EFI_ERROR_CODE(status));
+ return;
+ }
+
+ loaded_image->DeviceHandle = dev->devhandle;
+
+ if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
+ EFI_SUCCESS) {
+ printf("Failed to start image provided by %s (%lu)\n",
+ mod->name, EFI_ERROR_CODE(status));
+ return;
+ }
+}
+
+EFI_STATUS
+efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
+{
+ EFI_HANDLE *handles;
EFI_STATUS status;
- EFI_DEVICE_PATH *devpath;
- EFI_BOOT_SERVICES *BS;
EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL;
- const char *path = _PATH_LOADER;
+ UINTN i, max_dim, best_mode, cols, rows, hsize, nhandles;
+ /* Basic initialization*/
systab = Xsystab;
image = Ximage;
+ bs = Xsystab->BootServices;
- BS = systab->BootServices;
- status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
+ /* Set up the console, so printf works. */
+ status = bs->LocateProtocol(&ConsoleControlGUID, NULL,
(VOID **)&ConsoleControl);
if (status == EFI_SUCCESS)
(void)ConsoleControl->SetMode(ConsoleControl,
@@ -94,200 +173,162 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
conout->EnableCursor(conout, TRUE);
conout->ClearScreen(conout);
- printf("\n"
- ">> FreeBSD EFI boot block\n");
- printf(" Loader path: %s\n", path);
-
- status = systab->BootServices->LocateHandle(ByProtocol,
- &BlockIoProtocolGUID, NULL, &nparts, handles);
- nparts /= sizeof(handles[0]);
-
- for (i = 0; i < nparts; i++) {
- status = systab->BootServices->HandleProtocol(handles[i],
- &DevicePathGUID, (void **)&devpath);
- if (EFI_ERROR(status))
+ printf("\n>> FreeBSD EFI boot block\n");
+ printf(" Loader path: %s\n\n", _PATH_LOADER);
+ printf(" Initializing modules:");
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ if (boot_modules[i] == NULL)
continue;
- while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
- devpath = NextDevicePathNode(devpath);
+ printf(" %s", boot_modules[i]->name);
+ if (boot_modules[i]->init != NULL)
+ boot_modules[i]->init();
+ }
+ putchar('\n');
- status = systab->BootServices->HandleProtocol(handles[i],
- &BlockIoProtocolGUID, (void **)&blkio);
- if (EFI_ERROR(status))
- continue;
+ /* Get all the device handles */
+ hsize = (UINTN)NUM_HANDLES_INIT * sizeof(EFI_HANDLE);
+ if ((status = bs->AllocatePool(EfiLoaderData, hsize, (void **)&handles))
+ != EFI_SUCCESS)
+ panic("Failed to allocate %d handles (%lu)", NUM_HANDLES_INIT,
+ EFI_ERROR_CODE(status));
- if (!blkio->Media->LogicalPartition)
- continue;
+ status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID, NULL,
+ &hsize, handles);
+ switch (status) {
+ case EFI_SUCCESS:
+ break;
+ case EFI_BUFFER_TOO_SMALL:
+ (void)bs->FreePool(handles);
+ if ((status = bs->AllocatePool(EfiLoaderData, hsize,
+ (void **)&handles) != EFI_SUCCESS)) {
+ panic("Failed to allocate %zu handles (%lu)", hsize /
+ sizeof(*handles), EFI_ERROR_CODE(status));
+ }
+ status = bs->LocateHandle(ByProtocol, &BlockIoProtocolGUID,
+ NULL, &hsize, handles);
+ if (status != 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));
+ }
- if (domount(devpath, blkio, 1) >= 0)
+ /* Scan all partitions, probing with all modules. */
+ nhandles = hsize / sizeof(*handles);
+ printf(" Probing %zu block devices...", nhandles);
+ for (i = 0; i < nhandles; i++) {
+ status = probe_handle(handles[i]);
+ switch (status) {
+ case EFI_UNSUPPORTED:
+ printf(".");
+ break;
+ case EFI_SUCCESS:
+ printf("+");
break;
+ default:
+ printf("x");
+ break;
+ }
}
+ printf(" done\n");
- if (i == nparts)
- panic("No bootable partition found");
-
- bootdevhandle = handles[i];
- load(path);
+ /* Status summary. */
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ if (boot_modules[i] != NULL) {
+ printf(" ");
+ boot_modules[i]->status();
+ }
+ }
- panic("Load failed");
+ /* Select a partition to boot by trying each module in order. */
+ for (i = 0; i < NUM_BOOT_MODULES; i++)
+ if (boot_modules[i] != NULL)
+ try_load(boot_modules[i]);
- return EFI_SUCCESS;
+ /* If we get here, we're out of luck... */
+ panic("No bootable partitions found!");
}
-static int
-dskread(void *buf, u_int64_t lba, int nblk)
+static EFI_STATUS
+probe_handle(EFI_HANDLE h)
{
+ dev_info_t *devinfo;
+ EFI_BLOCK_IO *blkio;
+ EFI_DEVICE_PATH *devpath;
EFI_STATUS status;
- int size;
+ UINTN i;
- lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
- size = nblk * DEV_BSIZE;
- status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
- size, buf);
+ /* Figure out if we're dealing with an actual partition. */
+ status = bs->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
+ if (status == EFI_UNSUPPORTED)
+ return (status);
- if (EFI_ERROR(status))
- return (-1);
+ if (status != EFI_SUCCESS) {
+ DPRINTF("\nFailed to query DevicePath (%lu)\n",
+ EFI_ERROR_CODE(status));
+ return (status);
+ }
- return (0);
-}
+ while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
+ devpath = NextDevicePathNode(devpath);
-#include "ufsread.c"
+ status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
+ if (status == EFI_UNSUPPORTED)
+ return (status);
-static ssize_t
-fsstat(ufs_ino_t inode)
-{
-#ifndef UFS2_ONLY
- static struct ufs1_dinode dp1;
-#endif
-#ifndef UFS1_ONLY
- static struct ufs2_dinode dp2;
-#endif
- static struct fs fs;
- static ufs_ino_t inomap;
- char *blkbuf;
- void *indbuf;
- size_t n, size;
- static ufs2_daddr_t blkmap, indmap;
-
- blkbuf = dmadat->blkbuf;
- indbuf = dmadat->indbuf;
- if (!dsk_meta) {
- inomap = 0;
- for (n = 0; sblock_try[n] != -1; n++) {
- if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
- SBLOCKSIZE / DEV_BSIZE))
- return -1;
- memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
- if ((
-#if defined(UFS1_ONLY)
- fs.fs_magic == FS_UFS1_MAGIC
-#elif defined(UFS2_ONLY)
- (fs.fs_magic == FS_UFS2_MAGIC &&
- fs.fs_sblockloc == sblock_try[n])
-#else
- fs.fs_magic == FS_UFS1_MAGIC ||
- (fs.fs_magic == FS_UFS2_MAGIC &&
- fs.fs_sblockloc == sblock_try[n])
-#endif
- ) &&
- fs.fs_bsize <= MAXBSIZE &&
- fs.fs_bsize >= (int32_t)sizeof(struct fs))
- break;
- }
- if (sblock_try[n] == -1) {
- return -1;
- }
- dsk_meta++;
- } else
- memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
- if (!inode)
- return 0;
- if (inomap != inode) {
- n = IPERVBLK(&fs);
- if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
- return -1;
- n = INO_TO_VBO(n, inode);
-#if defined(UFS1_ONLY)
- memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
- sizeof(struct ufs1_dinode));
-#elif defined(UFS2_ONLY)
- memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
- sizeof(struct ufs2_dinode));
-#else
- if (fs.fs_magic == FS_UFS1_MAGIC)
- memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n,
- sizeof(struct ufs1_dinode));
- else
- memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n,
- sizeof(struct ufs2_dinode));
-#endif
- inomap = inode;
- fs_off = 0;
- blkmap = indmap = 0;
+ if (status != EFI_SUCCESS) {
+ DPRINTF("\nFailed to query BlockIoProtocol (%lu)\n",
+ EFI_ERROR_CODE(status));
+ return (status);
}
- size = DIP(di_size);
- n = size - fs_off;
- return (n);
-}
-static struct dmadat __dmadat;
+ if (!blkio->Media->LogicalPartition)
+ return (EFI_UNSUPPORTED);
-static int
-domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
-{
+ /* Run through each module, see if it can load this partition */
+ for (i = 0; i < NUM_BOOT_MODULES; i++) {
+ if (boot_modules[i] == NULL)
+ continue;
- dmadat = &__dmadat;
- bootdev = blkio;
- bootdevpath = device;
- if (fsread(0, NULL, 0)) {
- if (!quiet)
- printf("domount: can't read superblock\n");
- return (-1);
+ if ((status = bs->AllocatePool(EfiLoaderData,
+ sizeof(*devinfo), (void **)&devinfo)) !=
+ EFI_SUCCESS) {
+ DPRINTF("\nFailed to allocate devinfo (%lu)\n",
+ EFI_ERROR_CODE(status));
+ continue;
+ }
+ devinfo->dev = blkio;
+ devinfo->devpath = devpath;
+ devinfo->devhandle = h;
+ devinfo->devdata = NULL;
+ devinfo->next = NULL;
+
+ status = boot_modules[i]->probe(devinfo);
+ if (status == EFI_SUCCESS)
+ return (EFI_SUCCESS);
+ (void)bs->FreePool(devinfo);
}
- if (!quiet)
- printf("Succesfully mounted UFS filesystem\n");
- return (0);
+
+ return (EFI_UNSUPPORTED);
}
-static void
-load(const char *fname)
+void
+add_device(dev_info_t **devinfop, dev_info_t *devinfo)
{
- ufs_ino_t ino;
- EFI_STATUS status;
- EFI_HANDLE loaderhandle;
- EFI_LOADED_IMAGE *loaded_image;
- void *buffer;
- size_t bufsize;
+ dev_info_t *dev;
- if ((ino = lookup(fname)) == 0) {
- printf("File %s not found\n", fname);
+ if (*devinfop == NULL) {
+ *devinfop = devinfo;
return;
}
- bufsize = fsstat(ino);
- status = systab->BootServices->AllocatePool(EfiLoaderData,
- bufsize, &buffer);
- fsread(ino, buffer, bufsize);
+ for (dev = *devinfop; dev->next != NULL; dev = dev->next)
+ ;
- /* XXX: For secure boot, we need our own loader here */
- status = systab->BootServices->LoadImage(TRUE, image, bootdevpath,
- buffer, bufsize, &loaderhandle);
- if (EFI_ERROR(status))
- printf("LoadImage failed with error %lu\n",
- EFI_ERROR_CODE(status));
-
- status = systab->BootServices->HandleProtocol(loaderhandle,
- &LoadedImageGUID, (VOID**)&loaded_image);
- if (EFI_ERROR(status))
- printf("HandleProtocol failed with error %lu\n",
- EFI_ERROR_CODE(status));
-
- loaded_image->DeviceHandle = bootdevhandle;
-
- status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
- if (EFI_ERROR(status))
- printf("StartImage failed with error %lu\n",
- EFI_ERROR_CODE(status));
+ dev->next = devinfo;
}
void
diff --git a/sys/boot/efi/boot1/boot_module.h b/sys/boot/efi/boot1/boot_module.h
new file mode 100644
index 0000000..2c158f6
--- /dev/null
+++ b/sys/boot/efi/boot1/boot_module.h
@@ -0,0 +1,110 @@
+/*-
+ * 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 the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * 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, ...) printf(fmt, __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) {}
+#endif
+
+/* EFI device info */
+typedef struct dev_info
+{
+ EFI_BLOCK_IO *dev;
+ EFI_DEVICE_PATH *devpath;
+ EFI_HANDLE *devhandle;
+ void *devdata;
+ struct dev_info *next;
+} dev_info_t;
+
+/*
+ * A boot loader module.
+ *
+ * This is a standard interface for filesystem modules in the EFI system.
+ */
+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 = The module can handle the device.
+ * EFI_NOT_FOUND = The module can not handle the device.
+ * Other = 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 it.
+ *
+ * Return codes:
+ * EFI_SUCCESS = The module can handle the device.
+ * EFI_NOT_FOUND = The module can not handle the device.
+ * Other = The module encountered an error.
+ */
+ EFI_STATUS (*load)(const char *loader_path, dev_info_t **devinfo,
+ void **buf, size_t *bufsize);
+
+ /* status outputs information about the probed devices. */
+ void (*status)();
+
+} 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;
+
+#endif
diff --git a/sys/boot/efi/boot1/ufs_module.c b/sys/boot/efi/boot1/ufs_module.c
new file mode 100644
index 0000000..9181b6e
--- /dev/null
+++ b/sys/boot/efi/boot1/ufs_module.c
@@ -0,0 +1,254 @@
+/*-
+ * 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 the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * 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 = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
+ size = nblk * DEV_BSIZE;
+
+ status = devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, size, buf);
+
+ if (status != EFI_SUCCESS) {
+ DPRINTF("dskread: failed dev: %p, id: %u, lba: %lu, size: %d, "
+ "status: %lu\n", devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, size,
+ EFI_ERROR_CODE(status));
+ return (-1);
+ }
+
+ return (0);
+}
+
+#include "ufsread.c"
+
+static ssize_t
+fsstat(ufs_ino_t inode)
+{
+#ifndef UFS2_ONLY
+ static struct ufs1_dinode dp1;
+#endif
+#ifndef UFS1_ONLY
+ static struct ufs2_dinode dp2;
+#endif
+ static struct fs fs;
+ static ufs_ino_t inomap;
+ char *blkbuf;
+ void *indbuf;
+ size_t n, size;
+ static ufs2_daddr_t blkmap, indmap;
+
+ blkbuf = dmadat->blkbuf;
+ indbuf = dmadat->indbuf;
+ if (!dsk_meta) {
+ inomap = 0;
+ for (n = 0; sblock_try[n] != -1; n++) {
+ if (dskread(dmadat->sbbuf, sblock_try[n] / DEV_BSIZE,
+ SBLOCKSIZE / DEV_BSIZE))
+ return (-1);
+ memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+ if ((
+#if defined(UFS1_ONLY)
+ fs.fs_magic == FS_UFS1_MAGIC
+#elif defined(UFS2_ONLY)
+ (fs.fs_magic == FS_UFS2_MAGIC &&
+ fs.fs_sblockloc == sblock_try[n])
+#else
+ fs.fs_magic == FS_UFS1_MAGIC ||
+ (fs.fs_magic == FS_UFS2_MAGIC &&
+ fs.fs_sblockloc == sblock_try[n])
+#endif
+ ) &&
+ fs.fs_bsize <= MAXBSIZE &&
+ fs.fs_bsize >= (int32_t)sizeof(struct fs))
+ break;
+ }
+ if (sblock_try[n] == -1) {
+ return (-1);
+ }
+ dsk_meta++;
+ } else
+ memcpy(&fs, dmadat->sbbuf, sizeof(struct fs));
+ if (!inode)
+ return (0);
+ if (inomap != inode) {
+ n = IPERVBLK(&fs);
+ if (dskread(blkbuf, INO_TO_VBA(&fs, n, inode), DBPERVBLK))
+ return (-1);
+ n = INO_TO_VBO(n, inode);
+#if defined(UFS1_ONLY)
+ memcpy(&dp1, (struct ufs1_dinode *)blkbuf + n,
+ sizeof(struct ufs1_dinode));
+#elif defined(UFS2_ONLY)
+ memcpy(&dp2, (struct ufs2_dinode *)blkbuf + n,
+ sizeof(struct ufs2_dinode));
+#else
+ if (fs.fs_magic == FS_UFS1_MAGIC)
+ memcpy(&dp1, (struct ufs1_dinode *)(void *)blkbuf + n,
+ sizeof(struct ufs1_dinode));
+ else
+ memcpy(&dp2, (struct ufs2_dinode *)(void *)blkbuf + n,
+ sizeof(struct ufs2_dinode));
+#endif
+ inomap = inode;
+ fs_off = 0;
+ blkmap = indmap = 0;
+ }
+ size = DIP(di_size);
+ n = size - fs_off;
+
+ return (n);
+}
+
+static struct dmadat __dmadat;
+
+static EFI_STATUS
+probe(dev_info_t* dev)
+{
+
+ devinfo = dev;
+ dmadat = &__dmadat;
+ if (fsread(0, NULL, 0) < 0)
+ return (EFI_UNSUPPORTED);
+
+ add_device(&devices, dev);
+
+ return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+try_load(dev_info_t *dev, const char *loader_path, void **bufp, size_t *bufsize)
+{
+ ufs_ino_t ino;
+ EFI_STATUS status;
+ size_t size;
+ ssize_t read;
+ void *buf;
+
+ dsk_meta = 0;
+ devinfo = dev;
+ if ((ino = lookup(loader_path)) == 0)
+ return (EFI_NOT_FOUND);
+
+ size = fsstat(ino);
+ if (size <= 0) {
+ printf("Failed to fsstat %s ino: %d\n", loader_path, ino);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((status = bs->AllocatePool(EfiLoaderData, size, &buf)) !=
+ EFI_SUCCESS) {
+ printf("Failed to allocate read buffer (%lu)\n",
+ EFI_ERROR_CODE(status));
+ return (status);
+ }
+
+ read = fsread(ino, buf, size);
+ if ((size_t)read != size) {
+ printf("Failed to read %s (%zd != %zu)\n", loader_path, read,
+ size);
+ (void)bs->FreePool(buf);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ *bufp = buf;
+ *bufsize = size;
+
+ return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+load(const char *loader_path, dev_info_t **devinfop, void **buf,
+ size_t *bufsize)
+{
+ dev_info_t *dev;
+ EFI_STATUS status;
+
+ for (dev = devices; dev != NULL; dev = dev->next) {
+ status = try_load(dev, loader_path, buf, bufsize);
+ if (status == EFI_SUCCESS) {
+ *devinfop = dev;
+ return (EFI_SUCCESS);
+ } else if (status != EFI_NOT_FOUND) {
+ return (status);
+ }
+ }
+
+ return (EFI_NOT_FOUND);
+}
+
+static void
+status()
+{
+ int i;
+ dev_info_t *dev;
+
+ for (dev = devices, i = 0; dev != NULL; dev = 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);
+ }
+}
+
+const boot_module_t ufs_module =
+{
+ .name = "UFS",
+ .probe = probe,
+ .load = load,
+ .status = status
+};
diff --git a/sys/boot/efi/boot1/zfs_module.c b/sys/boot/efi/boot1/zfs_module.c
new file mode 100644
index 0000000..96eec33
--- /dev/null
+++ b/sys/boot/efi/boot1/zfs_module.c
@@ -0,0 +1,199 @@
+/*-
+ * 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 the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * 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 = (dev_info_t *)priv;
+ lba = off / devinfo->dev->Media->BlockSize;
+
+ status = devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, bytes, buf);
+ if (status != EFI_SUCCESS) {
+ DPRINTF("vdev_read: failed dev: %p, id: %u, lba: %zu, size: %zu,"
+ " status: %lu\n", devinfo->dev,
+ devinfo->dev->Media->MediaId, 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 = bs->AllocatePool(EfiLoaderData, sizeof(*dev),
+ (void**)&tdev)) != 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) != 0) {
+ (void)bs->FreePool(tdev);
+ return (EFI_UNSUPPORTED);
+ }
+
+ dev->devdata = spa;
+ add_device(&devices, dev);
+
+ return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+try_load(dev_info_t *devinfo, const char *loader_path, void **bufp, size_t *bufsize)
+{
+ spa_t *spa;
+ struct zfsmount zfsmount;
+ dnode_phys_t dn;
+ struct stat st;
+ int err;
+ void *buf;
+ EFI_STATUS status;
+
+ spa = devinfo->devdata;
+ if (zfs_spa_init(spa) != 0) {
+ /* Init failed, don't report this loudly. */
+ return (EFI_NOT_FOUND);
+ }
+
+ if (zfs_mount(spa, 0, &zfsmount) != 0) {
+ /* Mount failed, don't report this loudly. */
+ return (EFI_NOT_FOUND);
+ }
+
+ if ((err = zfs_lookup(&zfsmount, loader_path, &dn)) != 0) {
+ printf("Failed to lookup %s on pool %s (%d)\n", loader_path,
+ spa->spa_name, err);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) {
+ printf("Failed to lookup %s on pool %s (%d)\n", loader_path,
+ spa->spa_name, err);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((status = bs->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf))
+ != EFI_SUCCESS) {
+ printf("Failed to allocate load buffer for pool %s (%lu)\n",
+ spa->spa_name, EFI_ERROR_CODE(status));
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ if ((err = dnode_read(spa, &dn, 0, buf, st.st_size)) != 0) {
+ printf("Failed to read node from %s (%d)\n", spa->spa_name,
+ err);
+ (void)bs->FreePool(buf);
+ return (EFI_INVALID_PARAMETER);
+ }
+
+ *bufsize = st.st_size;
+ *bufp = buf;
+
+ return (EFI_SUCCESS);
+}
+
+static EFI_STATUS
+load(const char *loader_path, dev_info_t **devinfop, void **bufp,
+ size_t *bufsize)
+{
+ dev_info_t *devinfo;
+ EFI_STATUS status;
+
+ for (devinfo = devices; devinfo != NULL; devinfo = devinfo->next) {
+ status = try_load(devinfo, loader_path, bufp, bufsize);
+ if (status == EFI_SUCCESS) {
+ *devinfop = devinfo;
+ return (EFI_SUCCESS);
+ } else if (status != EFI_NOT_FOUND) {
+ return (status);
+ }
+ }
+
+ return (EFI_NOT_FOUND);
+}
+
+static void
+status()
+{
+ spa_t *spa;
+
+ spa = STAILQ_FIRST(&zfs_pools);
+ if (spa == 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()
+{
+
+ zfs_init();
+}
+
+const boot_module_t zfs_module =
+{
+ .name = "ZFS",
+ .init = init,
+ .probe = probe,
+ .load = load,
+ .status = status
+};
diff --git a/sys/boot/efi/fdt/Makefile b/sys/boot/efi/fdt/Makefile
index 4d82a86..15862dc 100644
--- a/sys/boot/efi/fdt/Makefile
+++ b/sys/boot/efi/fdt/Makefile
@@ -7,8 +7,6 @@
LIB= efi_fdt
INTERNALLIB=
WARNS?= 6
-CWARNFLAGS.gcc+= -Wno-strict-prototypes
-CWARNFLAGS.gcc+= -Wno-redundant-decls
SRCS= efi_fdt.c
diff --git a/sys/boot/efi/include/efilib.h b/sys/boot/efi/include/efilib.h
index b67ffc5..ba5b663 100644
--- a/sys/boot/efi/include/efilib.h
+++ b/sys/boot/efi/include/efilib.h
@@ -39,11 +39,11 @@ extern struct devsw efinet_dev;
extern struct netif_driver efinetif;
void *efi_get_table(EFI_GUID *tbl);
-void efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table);
int efi_register_handles(struct devsw *, EFI_HANDLE *, EFI_HANDLE *, int);
EFI_HANDLE efi_find_handle(struct devsw *, int);
-int efi_handle_lookup(EFI_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_status_to_errno(EFI_STATUS);
time_t efi_time(EFI_TIME *);
diff --git a/sys/boot/efi/libefi/Makefile b/sys/boot/efi/libefi/Makefile
index 6df7817..bb2f9ea 100644
--- a/sys/boot/efi/libefi/Makefile
+++ b/sys/boot/efi/libefi/Makefile
@@ -3,7 +3,6 @@
LIB= efi
INTERNALLIB=
WARNS?= 2
-CWARNFLAGS.gcc+= -Wno-attributes
SRCS= delay.c efi_console.c efinet.c efipart.c errno.c handles.c \
libefi.c time.c
diff --git a/sys/boot/efi/libefi/handles.c b/sys/boot/efi/libefi/handles.c
index b15c0a5..1e4ef6f 100644
--- a/sys/boot/efi/libefi/handles.c
+++ b/sys/boot/efi/libefi/handles.c
@@ -35,6 +35,7 @@ struct entry {
EFI_HANDLE alias;
struct devsw *dev;
int unit;
+ uint64_t extra;
};
struct entry *entry;
@@ -79,7 +80,7 @@ efi_find_handle(struct devsw *dev, int unit)
}
int
-efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit)
+efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit, uint64_t *extra)
{
int idx;
@@ -90,7 +91,28 @@ efi_handle_lookup(EFI_HANDLE h, struct devsw **dev, int *unit)
*dev = entry[idx].dev;
if (unit != NULL)
*unit = entry[idx].unit;
+ if (extra != NULL)
+ *extra = entry[idx].extra;
return (0);
}
return (ENOENT);
}
+
+int
+efi_handle_update_dev(EFI_HANDLE h, struct devsw *dev, int unit,
+ uint64_t guid)
+{
+ int idx;
+
+ for (idx = 0; idx < nentries; idx++) {
+ if (entry[idx].handle != h)
+ continue;
+ entry[idx].dev = dev;
+ entry[idx].unit = unit;
+ entry[idx].alias = NULL;
+ entry[idx].extra = guid;
+ return (0);
+ }
+
+ return (ENOENT);
+}
diff --git a/sys/boot/efi/loader/Makefile b/sys/boot/efi/loader/Makefile
index 56f3cab..d36e54b 100644
--- a/sys/boot/efi/loader/Makefile
+++ b/sys/boot/efi/loader/Makefile
@@ -4,9 +4,6 @@ MAN=
.include <src.opts.mk>
-# In-tree GCC does not support __attribute__((ms_abi)).
-.if ${COMPILER_TYPE} != "gcc"
-
MK_SSP= no
PROG= loader.sym
@@ -24,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
@@ -36,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
@@ -113,8 +125,6 @@ DPADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND} \
${LDSCRIPT}
LDADD= ${LIBFICL} ${LIBEFI} ${LIBFDT} ${LIBEFI_FDT} ${LIBSTAND}
-.endif # ${COMPILER_TYPE} != "gcc"
-
.include <bsd.prog.mk>
beforedepend ${OBJS}: machine
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 45f9871..8fc80eb 100644
--- a/sys/boot/efi/loader/devicename.c
+++ b/sys/boot/efi/loader/devicename.c
@@ -31,7 +31,11 @@ __FBSDID("$FreeBSD$");
#include <stand.h>
#include <string.h>
#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>
@@ -86,7 +90,7 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
struct devsw *dv;
char *cp;
const char *np;
- int i, err;
+ int i;
/* minimum length check */
if (strlen(devspec) < 2)
@@ -101,24 +105,43 @@ efi_parsedev(struct devdesc **dev, const char *devspec, const char **path)
if (devsw[i] == NULL)
return (ENOENT);
- idev = malloc(sizeof(struct devdesc));
- if (idev == NULL)
- return (ENOMEM);
+ np = devspec + strlen(dv->dv_name);
- idev->d_dev = dv;
- idev->d_type = dv->dv_type;
- idev->d_unit = -1;
+#ifdef EFI_ZFS_BOOT
+ if (dv->dv_type == DEVT_ZFS) {
+ int err;
- err = 0;
- np = devspec + strlen(dv->dv_name);
- if (*np != '\0' && *np != ':') {
- idev->d_unit = strtol(np, &cp, 0);
- if (cp == np) {
- idev->d_unit = -1;
+ 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 (EUNIT);
+ return (err);
+ }
+ *dev = idev;
+ cp = strchr(np + 1, ':');
+ } else
+#endif
+ {
+ idev = malloc(sizeof(struct devdesc));
+ if (idev == NULL)
+ return (ENOMEM);
+
+ idev->d_dev = dv;
+ idev->d_type = dv->dv_type;
+ idev->d_unit = -1;
+ if (*np != '\0' && *np != ':') {
+ idev->d_unit = strtol(np, &cp, 0);
+ if (cp == np) {
+ idev->d_unit = -1;
+ free(idev);
+ return (EUNIT);
+ }
}
}
+
if (*cp != '\0' && *cp != ':') {
free(idev);
return (EINVAL);
@@ -137,9 +160,13 @@ char *
efi_fmtdev(void *vdev)
{
struct devdesc *dev = (struct devdesc *)vdev;
- static char buf[32]; /* XXX device length constant? */
+ 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 ddd96b4..0b9dcf6 100644
--- a/sys/boot/efi/loader/main.c
+++ b/sys/boot/efi/loader/main.c
@@ -28,6 +28,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
#include <stand.h>
#include <string.h>
#include <setjmp.h>
@@ -38,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[];
@@ -45,7 +50,6 @@ extern char bootprog_rev[];
extern char bootprog_date[];
extern char bootprog_maker[];
-struct devdesc currdev; /* our current device */
struct arch_switch archsw; /* MI/MD interface boundary */
EFI_GUID acpi = ACPI_TABLE_GUID;
@@ -61,15 +65,45 @@ 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
+ * don't support support wide characters either.
+ */
+static void
+print_str16(const CHAR16 *str)
+{
+ int i;
+
+ for (i = 0; str[i]; i++)
+ printf("%c", (char)str[i]);
+}
+
EFI_STATUS
main(int argc, CHAR16 *argv[])
{
char var[128];
EFI_LOADED_IMAGE *img;
EFI_GUID *guid;
- int i, j, vargood;
+ int i, j, vargood, unit;
+ struct devsw *dev;
+ uint64_t pool_guid;
UINTN k;
+ archsw.arch_autoload = efi_autoload;
+ archsw.arch_getdev = efi_getdev;
+ 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
* early, but some console attributes may depend on reading from
@@ -116,6 +150,13 @@ main(int argc, CHAR16 *argv[])
/* Get our loaded image protocol interface structure. */
BS->HandleProtocol(IH, &imgid, (VOID**)&img);
+ printf("Command line arguments:");
+ for (i = 0; i < argc; i++) {
+ printf(" ");
+ print_str16(argv[i]);
+ }
+ printf("\n");
+
printf("Image base: 0x%lx\n", (u_long)img->ImageBase);
printf("EFI version: %d.%02d\n", ST->Hdr.Revision >> 16,
ST->Hdr.Revision & 0xffff);
@@ -129,9 +170,6 @@ main(int argc, CHAR16 *argv[])
printf("%s, Revision %s\n", bootprog_name, bootprog_rev);
printf("(%s, %s)\n", bootprog_maker, bootprog_date);
- efi_handle_lookup(img->DeviceHandle, &currdev.d_dev, &currdev.d_unit);
- currdev.d_type = currdev.d_dev->dv_type;
-
/*
* Disable the watchdog timer. By default the boot manager sets
* the timer to 5 minutes before invoking a boot option. If we
@@ -143,19 +181,45 @@ main(int argc, CHAR16 *argv[])
*/
BS->SetWatchdogTimer(0, 0, 0, NULL);
- env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
- efi_setcurrdev, env_nounset);
- env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
- env_nounset);
+ 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);
+ init_zfs_bootenv(zfs_fmtdev(&currdev));
+ break;
+ }
+#endif
+ default: {
+ struct devdesc currdev;
+
+ currdev.d_dev = dev;
+ currdev.d_unit = unit;
+ currdev.d_opendata = NULL;
+ currdev.d_type = currdev.d_dev->dv_type;
+ env_setenv("currdev", EV_VOLATILE, efi_fmtdev(&currdev),
+ efi_setcurrdev, env_nounset);
+ env_setenv("loaddev", EV_VOLATILE, efi_fmtdev(&currdev), env_noset,
+ env_nounset);
+ break;
+ }
+ }
setenv("LINES", "24", 1); /* optional */
- archsw.arch_autoload = efi_autoload;
- archsw.arch_getdev = efi_getdev;
- archsw.arch_copyin = efi_copyin;
- archsw.arch_copyout = efi_copyout;
- archsw.arch_readin = efi_readin;
-
for (k = 0; k < ST->NumberOfTableEntries; k++) {
guid = &ST->ConfigurationTable[k].VendorGuid;
if (!memcmp(guid, &smbios, sizeof(EFI_GUID))) {
@@ -423,6 +487,61 @@ 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);
+}
+
+COMMAND_SET(reloadbe, "reloadbe", "refresh the list of ZFS Boot Environments",
+ command_reloadbe);
+
+static int
+command_reloadbe(int argc, char *argv[])
+{
+ int err;
+ char *root;
+
+ if (argc > 2) {
+ command_errmsg = "wrong number of arguments";
+ return (CMD_ERROR);
+ }
+
+ if (argc == 2) {
+ err = zfs_bootenv(argv[1]);
+ } else {
+ root = getenv("zfs_be_root");
+ if (root == NULL) {
+ return (CMD_OK);
+ }
+ err = zfs_bootenv(root);
+ }
+
+ 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[]);
@@ -441,3 +560,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
diff --git a/sys/boot/fdt/fdt_loader_cmd.c b/sys/boot/fdt/fdt_loader_cmd.c
index 0ce8f15..a1eaf9d 100644
--- a/sys/boot/fdt/fdt_loader_cmd.c
+++ b/sys/boot/fdt/fdt_loader_cmd.c
@@ -464,7 +464,7 @@ fdt_fixup_memory(struct fdt_mem_region *region, size_t num)
{
struct fdt_mem_region *curmr;
uint32_t addr_cells, size_cells;
- uint32_t *addr_cellsp, *reg, *size_cellsp;
+ uint32_t *addr_cellsp, *size_cellsp;
int err, i, len, memory, root;
size_t realmrno;
uint8_t *buf, *sb;
diff --git a/sys/boot/i386/loader/main.c b/sys/boot/i386/loader/main.c
index 644747e..c0782fc 100644
--- a/sys/boot/i386/loader/main.c
+++ b/sys/boot/i386/loader/main.c
@@ -69,7 +69,6 @@ static int isa_inb(int port);
static void isa_outb(int port, int value);
void exit(int code);
#ifdef LOADER_ZFS_SUPPORT
-static void init_zfs_bootenv(char *currdev);
static void i386_zfs_probe(void);
#endif
@@ -306,34 +305,6 @@ extract_currdev(void)
env_nounset);
}
-#ifdef LOADER_ZFS_SUPPORT
-static void
-init_zfs_bootenv(char *currdev)
-{
- char *beroot;
-
- if (strlen(currdev) == 0)
- return;
- if(strncmp(currdev, "zfs:", 4) != 0)
- return;
- /* Remove the trailing : */
- currdev[strlen(currdev) - 1] = '\0';
- setenv("zfs_be_active", currdev, 1);
- setenv("zfs_be_currpage", "1", 1);
- /* Do not overwrite if already set */
- setenv("vfs.root.mountfrom", currdev, 0);
- /* Forward past zfs: */
- currdev = strchr(currdev, ':');
- currdev++;
- /* Remove the last element (current bootenv) */
- beroot = strrchr(currdev, '/');
- if (beroot != NULL)
- beroot[0] = '\0';
- beroot = currdev;
- setenv("zfs_be_root", beroot, 1);
-}
-#endif
-
COMMAND_SET(reboot, "reboot", "reboot the system", command_reboot);
static int
diff --git a/sys/boot/userboot/test/test.c b/sys/boot/userboot/test/test.c
index d7ec3e4..d5707de 100644
--- a/sys/boot/userboot/test/test.c
+++ b/sys/boot/userboot/test/test.c
@@ -414,7 +414,7 @@ void
usage()
{
- printf("usage: [-d <disk image path>] [-h <host filesystem path>\n");
+ printf("usage: [-b <userboot shared object>] [-d <disk image path>] [-h <host filesystem path>\n");
exit(1);
}
@@ -425,9 +425,14 @@ main(int argc, char** argv)
void (*func)(struct loader_callbacks *, void *, int, int);
int opt;
char *disk_image = NULL;
+ const char *userboot_obj = "/boot/userboot.so";
- while ((opt = getopt(argc, argv, "d:h:")) != -1) {
+ while ((opt = getopt(argc, argv, "b:d:h:")) != -1) {
switch (opt) {
+ case 'b':
+ userboot_obj = optarg;
+ break;
+
case 'd':
disk_image = optarg;
break;
@@ -441,8 +446,7 @@ main(int argc, char** argv)
}
}
- h = dlopen("/boot/userboot.so",
- RTLD_LOCAL);
+ h = dlopen(userboot_obj, RTLD_LOCAL);
if (!h) {
printf("%s\n", dlerror());
return (1);
diff --git a/sys/boot/userboot/userboot/main.c b/sys/boot/userboot/userboot/main.c
index a52550c..e64bbc7 100644
--- a/sys/boot/userboot/userboot/main.c
+++ b/sys/boot/userboot/userboot/main.c
@@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$");
static void userboot_zfs_probe(void);
static int userboot_zfs_found;
-static void init_zfs_bootenv(char *currdev);
#endif
#define USERBOOT_VERSION USERBOOT_VERSION_3
@@ -200,32 +199,6 @@ extract_currdev(void)
#if defined(USERBOOT_ZFS_SUPPORT)
static void
-init_zfs_bootenv(char *currdev)
-{
- char *beroot;
-
- if (strlen(currdev) == 0)
- return;
- if(strncmp(currdev, "zfs:", 4) != 0)
- return;
- /* Remove the trailing : */
- currdev[strlen(currdev) - 1] = '\0';
- setenv("zfs_be_active", currdev, 1);
- setenv("zfs_be_currpage", "1", 1);
- /* Do not overwrite if already set */
- setenv("vfs.root.mountfrom", currdev, 0);
- /* Forward past zfs: */
- currdev = strchr(currdev, ':');
- currdev++;
- /* Remove the last element (current bootenv) */
- beroot = strrchr(currdev, '/');
- if (beroot != NULL)
- beroot[0] = '\0';
- beroot = currdev;
- setenv("zfs_be_root", beroot, 1);
-}
-
-static void
userboot_zfs_probe(void)
{
char devname[32];
diff --git a/sys/boot/zfs/libzfs.h b/sys/boot/zfs/libzfs.h
index b289849..ee64d1c 100644
--- a/sys/boot/zfs/libzfs.h
+++ b/sys/boot/zfs/libzfs.h
@@ -62,6 +62,7 @@ int zfs_parsedev(struct zfs_devdesc *dev, const char *devspec,
char *zfs_fmtdev(void *vdev);
int zfs_probe_dev(const char *devname, uint64_t *pool_guid);
int zfs_list(const char *name);
+void init_zfs_bootenv(char *currdev);
int zfs_bootenv(const char *name);
int zfs_belist_add(const char *name);
int zfs_set_env(void);
diff --git a/sys/boot/zfs/zfs.c b/sys/boot/zfs/zfs.c
index c8b1284..8e6d420 100644
--- a/sys/boot/zfs/zfs.c
+++ b/sys/boot/zfs/zfs.c
@@ -709,6 +709,32 @@ zfs_list(const char *name)
return (zfs_list_dataset(spa, objid));
}
+void
+init_zfs_bootenv(char *currdev)
+{
+ char *beroot;
+
+ if (strlen(currdev) == 0)
+ return;
+ if(strncmp(currdev, "zfs:", 4) != 0)
+ return;
+ /* Remove the trailing : */
+ currdev[strlen(currdev) - 1] = '\0';
+ setenv("zfs_be_active", currdev, 1);
+ setenv("zfs_be_currpage", "1", 1);
+ /* Do not overwrite if already set */
+ setenv("vfs.root.mountfrom", currdev, 0);
+ /* Forward past zfs: */
+ currdev = strchr(currdev, ':');
+ currdev++;
+ /* Remove the last element (current bootenv) */
+ beroot = strrchr(currdev, '/');
+ if (beroot != NULL)
+ beroot[0] = '\0';
+ beroot = currdev;
+ setenv("zfs_be_root", beroot, 1);
+}
+
int
zfs_bootenv(const char *name)
{
@@ -779,8 +805,15 @@ int
zfs_belist_add(const char *name)
{
+ /* Skip special datasets that start with a $ character */
+ if (strncmp(name, "$", 1) == 0) {
+ return (0);
+ }
/* Add the boot environment to the head of the SLIST */
zfs_be = malloc(sizeof(struct zfs_be_entry));
+ if (zfs_be == NULL) {
+ return (ENOMEM);
+ }
zfs_be->name = name;
SLIST_INSERT_HEAD(&zfs_be_head, zfs_be, entries);
zfs_env_count++;
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index 927fbad..aa1a789 100644
--- a/sys/boot/zfs/zfsimpl.c
+++ b/sys/boot/zfs/zfsimpl.c
@@ -2165,7 +2165,13 @@ zfs_lookup(const struct zfsmount *mount, const char *upath, dnode_phys_t *dnode)
strcpy(&path[sb.st_size], p);
else
path[sb.st_size] = 0;
- if (sb.st_size + sizeof(znode_phys_t) <= dn.dn_bonuslen) {
+ /*
+ * Second test is purely to silence bogus compiler
+ * warning about accessing past the end of dn_bonus.
+ */
+ if (sb.st_size + sizeof(znode_phys_t) <=
+ dn.dn_bonuslen && sizeof(znode_phys_t) <=
+ sizeof(dn.dn_bonus)) {
memcpy(path, &dn.dn_bonus[sizeof(znode_phys_t)],
sb.st_size);
} else {
OpenPOWER on IntegriCloud