Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137798404
D4515.id12055.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
42 KB
Referenced Files
None
Subscribers
None
D4515.id12055.diff
View Options
Index: sys/boot/common/self_reloc.c
===================================================================
--- sys/boot/common/self_reloc.c
+++ sys/boot/common/self_reloc.c
@@ -61,6 +61,8 @@
#define RELOC_TYPE_RELATIVE R_386_RELATIVE
#endif
+void self_reloc(Elf_Addr baseaddr, ElfW_Dyn *dynamic);
+
/*
* A simple elf relocator.
*/
Index: sys/boot/efi/Makefile
===================================================================
--- sys/boot/efi/Makefile
+++ sys/boot/efi/Makefile
@@ -16,4 +16,6 @@
SUBDIR+= loader boot1
.endif
+CWARNFLAGS+= -Wall
+
.include <bsd.subdir.mk>
Index: sys/boot/efi/boot1/Makefile
===================================================================
--- sys/boot/efi/boot1/Makefile
+++ sys/boot/efi/boot1/Makefile
@@ -2,7 +2,19 @@
MAN=
+CWARNFLAGS?= -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes \
+ -Wmissing-prototypes -Wpointer-arith -Winline \
+ -Wundef -Wno-pointer-sign -Wmissing-include-dirs \
+ -fdiagnostics-show-option -Wno-unknown-pragmas \
+
+
+# EFI_GUID assignments
+CWARNFLAGS+= -Wno-missing-braces
+# zfsimpl.c
+CWARNFLAGS+= -Wno-unused-function -Wno-array-bounds
+
.include <bsd.own.mk>
+.include <src.opts.mk>
# In-tree GCC does not support __attribute__((ms_abi)).
.if ${COMPILER_TYPE} != "gcc"
@@ -13,13 +25,22 @@
INTERNALPROG=
# 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
+.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}
@@ -41,14 +62,13 @@
LDFLAGS+= -Wl,-znocombreloc
.endif
-.if ${MACHINE_CPUARCH} == "arm" || ${MACHINE_CPUARCH} == "i386"
#
# Add libstand for the runtime functions used by the compiler - for example
# __aeabi_* (arm) or __divdi3 (i386).
+# as well as required string and memory functions for all platforms.
#
DPADD+= ${LIBSTAND}
LDADD+= -lstand
-.endif
DPADD+= ${LDSCRIPT}
Index: sys/boot/efi/boot1/boot1.c
===================================================================
--- sys/boot/efi/boot1/boot1.c
+++ 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,17 +23,24 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/dirent.h>
#include <machine/elf.h>
#include <machine/stdarg.h>
#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
+#ifdef EFI_DEBUG
+#define DPRINTF(fmt, args...) \
+ do { \
+ printf(fmt, ##args) \
+ } while (0)
+#else
+#define DPRINTF(fmt, args...) {}
+#endif
typedef int putc_func_t(char c, void *arg);
@@ -41,58 +50,49 @@
u_int sp_size;
};
-static const char digits[] = "0123456789abcdef";
+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
-static void panic(const char *fmt, ...) __dead2;
-static int printf(const char *fmt, ...);
-static int putchar(char c, void *arg);
-static int vprintf(const char *fmt, va_list ap);
-static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
+static const char digits[] = "0123456789abcdef";
static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
-static int __putc(char c, void *arg);
static int __puts(const char *s, putc_func_t *putc, void *arg);
static int __sputc(char c, void *arg);
static char *__uitoa(char *buf, u_int val, int base);
static char *__ultoa(char *buf, u_long val, int base);
+static int putchr(char c, void *arg);
-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 void
-bcopy(const void *src, void *dst, size_t len)
-{
- const char *s = src;
- char *d = dst;
-
- while (len-- != 0)
- *d++ = *s++;
-}
-
-static void
-memcpy(void *dst, const void *src, size_t len)
+static int
+putchr(char c, void *arg)
{
- bcopy(src, dst, len);
-}
+ CHAR16 buf[2];
-static void
-bzero(void *b, size_t len)
-{
- char *p = b;
+ if (c == '\n')
+ putchr('\r', arg);
- while (len-- != 0)
- *p++ = 0;
-}
+ buf[0] = c;
+ buf[1] = 0;
+ systab->ConOut->OutputString(systab->ConOut, buf);
-static int
-strcmp(const char *s1, const char *s2)
-{
- for (; *s1 == *s2 && *s1; s1++, s2++)
- ;
- return ((u_char)*s1 - (u_char)*s2);
+ return (1);
}
static EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
@@ -100,27 +100,70 @@
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;
+/*
+ * 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: %lu, (%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;
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
+ if ((status = bs->StartImage(loaderhandle, NULL, NULL)) !=
+ EFI_SUCCESS) {
+ printf("Failed start image provided by %s (%lu)\n", mod->name,
+ EFI_ERROR_CODE(status));
+ return;
+ }
+}
+
+void
+efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
{
- EFI_HANDLE handles[128];
- EFI_BLOCK_IO *blkio;
- UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
+ 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;
- 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,
@@ -145,208 +188,165 @@
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();
+ }
+ putchr('\n', NULL);
- 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 %lu handles (%lu)", hsize /
+ sizeof(*handles), 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 %lu 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;
- ufs1_daddr_t addr1;
-#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, nb, size, off, vboff;
- ufs_lbn_t lbn;
- ufs2_daddr_t addr2, vbaddr;
- static ufs2_daddr_t blkmap, indmap;
- u_int u;
-
- 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 >= sizeof(struct fs))
- break;
- }
- if (sblock_try[n] == -1) {
- printf("Not ufs\n");
- 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 *)blkbuf + n,
- sizeof(struct ufs1_dinode));
- else
- memcpy(&dp2, (struct ufs2_dinode *)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);
-
- /* 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;
+ for (dev = *devinfop; dev->next != NULL; dev = dev->next)
+ ;
- 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;
}
-static void
+void
panic(const char *fmt, ...)
{
char buf[128];
@@ -360,7 +360,7 @@
while (1) {}
}
-static int
+int
printf(const char *fmt, ...)
{
va_list ap;
@@ -371,38 +371,17 @@
return 0;
va_start(ap, fmt);
- ret = vprintf(fmt, ap);
+ ret = __printf(fmt, putchr, 0, ap);
va_end(ap);
return (ret);
}
-static int
-putchar(char c, void *arg)
-{
- CHAR16 buf[2];
-
- if (c == '\n') {
- buf[0] = '\r';
- buf[1] = 0;
- systab->ConOut->OutputString(systab->ConOut, buf);
- }
- buf[0] = c;
- buf[1] = 0;
- systab->ConOut->OutputString(systab->ConOut, buf);
- return (1);
-}
-
-static int
-vprintf(const char *fmt, va_list ap)
+void vprintf(const char *fmt, va_list ap)
{
- int ret;
-
- ret = __printf(fmt, putchar, 0, ap);
- return (ret);
+ __printf(fmt, putchr, 0, ap);
}
-static int
-vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
+int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
{
struct sp_data sp;
int ret;
@@ -418,15 +397,10 @@
__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
{
char buf[(sizeof(long) * 8) + 1];
- char *nbuf;
+ char *nbuf, *s;
u_long ul;
u_int ui;
- int lflag;
- int sflag;
- char *s;
- int pad;
- int ret;
- int c;
+ int lflag, sflag, pad, ret, c;
nbuf = &buf[sizeof buf - 1];
ret = 0;
Index: sys/boot/efi/boot1/boot_module.h
===================================================================
--- /dev/null
+++ sys/boot/efi/boot1/boot_module.h
@@ -0,0 +1,113 @@
+/*-
+ * 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, args...) \
+ do { \
+ printf(fmt, ##args) \
+ } while (0)
+#else
+#define DPRINTF(fmt, args...) {}
+#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
Index: sys/boot/efi/boot1/ufs_module.c
===================================================================
--- /dev/null
+++ sys/boot/efi/boot1/ufs_module.c
@@ -0,0 +1,245 @@
+/*-
+ * 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;
+
+ lba = lba / (devinfo->dev->Media->BlockSize / DEV_BSIZE);
+ size = nblk * DEV_BSIZE;
+
+ if (devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, size, buf) != EFI_SUCCESS)
+ 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 >= 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 *)blkbuf + n,
+ sizeof(struct ufs1_dinode));
+ else
+ memcpy(&dp2, (struct ufs2_dinode *)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;
+
+ 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 (%ld != %lu)\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 *devinfo;
+ EFI_STATUS status;
+
+ for (devinfo = devices; devinfo != NULL; devinfo = devinfo->next) {
+ status = try_load(devinfo, loader_path, buf, 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()
+{
+ 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
+};
Index: sys/boot/efi/boot1/zfs_module.c
===================================================================
--- /dev/null
+++ sys/boot/efi/boot1/zfs_module.c
@@ -0,0 +1,192 @@
+/*-
+ * 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;
+
+ devinfo = (dev_info_t *)priv;
+ lba = off / devinfo->dev->Media->BlockSize;
+
+ if (devinfo->dev->ReadBlocks(devinfo->dev,
+ devinfo->dev->Media->MediaId, lba, bytes, buf) != EFI_SUCCESS)
+ 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
+};
Index: sys/boot/efi/include/efilib.h
===================================================================
--- sys/boot/efi/include/efilib.h
+++ sys/boot/efi/include/efilib.h
@@ -43,7 +43,8 @@
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 *);
Index: sys/boot/efi/libefi/handles.c
===================================================================
--- sys/boot/efi/libefi/handles.c
+++ sys/boot/efi/libefi/handles.c
@@ -35,6 +35,7 @@
EFI_HANDLE alias;
struct devsw *dev;
int unit;
+ uint64_t extra;
};
struct entry *entry;
@@ -79,7 +80,7 @@
}
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 @@
*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);
+}
Index: sys/boot/efi/loader/Makefile
===================================================================
--- sys/boot/efi/loader/Makefile
+++ sys/boot/efi/loader/Makefile
@@ -23,6 +23,11 @@
smbios.c \
vers.c
+.if ${MK_ZFS} != "no"
+SRCS+= zfs.c
+.PATH: ${.CURDIR}/../../zfs
+.endif
+
.PATH: ${.CURDIR}/arch/${MACHINE}
# For smbios.c
.PATH: ${.CURDIR}/../../i386/libi386
@@ -35,6 +40,13 @@
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
+# For zfsimpl.c
+CWARNFLAGS+= -Wno-array-bounds
+.endif
CFLAGS+= -DNO_PCI -DEFI
# make buildenv doesn't set DESTDIR, this means LIBSTAND
Index: sys/boot/efi/loader/conf.c
===================================================================
--- sys/boot/efi/loader/conf.c
+++ sys/boot/efi/loader/conf.c
@@ -31,14 +31,23 @@
#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,
Index: sys/boot/efi/loader/devicename.c
===================================================================
--- sys/boot/efi/loader/devicename.c
+++ sys/boot/efi/loader/devicename.c
@@ -31,7 +31,11 @@
#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>
@@ -84,7 +88,7 @@
struct devsw *dv;
char *cp;
const char *np;
- int i, err;
+ int i;
/* minimum length check */
if (strlen(devspec) < 2)
@@ -99,24 +103,44 @@
if (devsw[i] == NULL)
return (ENOENT);
- idev = malloc(sizeof(struct devdesc));
- if (idev == NULL)
- return (ENOMEM);
-
- idev->d_dev = dv;
- idev->d_type = dv->dv_type;
- idev->d_unit = -1;
-
- 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;
+
+#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 (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);
+ }
+ }
+#ifdef EFI_ZFS_BOOT
}
+#endif
+
if (*cp != '\0' && *cp != ':') {
free(idev);
return (EINVAL);
@@ -135,9 +159,13 @@
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;
Index: sys/boot/efi/loader/main.c
===================================================================
--- sys/boot/efi/loader/main.c
+++ 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 @@
#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_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,13 +65,43 @@
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;
+
+ 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
@@ -115,6 +149,13 @@
/* 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);
@@ -128,9 +169,6 @@
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
@@ -142,18 +180,43 @@
*/
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);
- setenv("LINES", "24", 1); /* optional */
+ 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;
- 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;
+ 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 */
for (i = 0; i < ST->NumberOfTableEntries; i++) {
guid = &ST->ConfigurationTable[i].VendorGuid;
@@ -421,6 +484,29 @@
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[]);
@@ -439,3 +525,23 @@
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
Index: sys/boot/zfs/zfsimpl.c
===================================================================
--- sys/boot/zfs/zfsimpl.c
+++ sys/boot/zfs/zfsimpl.c
@@ -1867,7 +1867,7 @@
return (zap_list(spa, &child_dir_zap) != 0);
}
-int
+static int
zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *name))
{
uint64_t dir_obj, child_dir_zapobj, zap_type;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Wed, Nov 26, 10:11 PM (11 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26232669
Default Alt Text
D4515.id12055.diff (42 KB)
Attached To
Mode
D4515: ZFS EFI Boot Support #2
Attached
Detach File
Event Timeline
Log In to Comment