Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Apr 2015 10:50:15 -0400
From:      Eric McCorkle <eric@metricspace.net>
To:        freebsd-hackers@freebsd.org
Subject:   Re: ZFS support for EFI
Message-ID:  <55311DA7.8080209@metricspace.net>
In-Reply-To: <55189CBA.9040107@metricspace.net>
References:  <55189CBA.9040107@metricspace.net>

next in thread | previous in thread | raw e-mail | index | archive | help
This is a multi-part message in MIME format.
--------------030702070506070109040607
Content-Type: text/plain; charset=windows-1252
Content-Transfer-Encoding: 7bit

I did some work on this last weekend.  I've got the zfs-enabled boot1
loading the ZFS uberblock, but it stops somewhere in the vdev_probe
code, believing the block to be a log.

I've attached a patch if anyone wants to play around with it.

Also, if someone with a UFS system could test that the modularization
didn't break UFS functionality, that'd be helpful.

On 03/29/2015 08:45 PM, Eric McCorkle wrote:
> Hi folks,
> 
> I've been messing around off and on for a while with adding ZFS support
> to the EFI boot.  It's been mostly exploratory and self-contained up to
> this point, but I've gotten to a point that warrants some discussion.
> 
> 
> First, I've converted boot1.c (the EFI boot block) to use an FS module
> framework.  This facilitates the addition of ZFS, and should also come
> in handy if someone wants to add other functionality later (ie. crypto,
> netboot, etc.)
> 
> 
> More importantly, the EFI loader doesn't seem to make use of its
> command-line arguments at all.  But a ZFS-enabled loader would really
> need the ability to take arguments from boot1 (or grub, or whatever
> else).  On the boot1 side, with ZFS you need to load and parse
> /boot/loader.conf (which may cause you to switch pools), then hand off
> the information to loader.  In the BIOS loader, that's done through a
> binary data object that gets passed in.  Command-line strings seem like
> the most sensible way to do it with EFI.
> 
> Would this be the right way to go, and if so, what ought these
> command-line strings look like?
> 
> 
> Thanks,
> Eric
> _______________________________________________
> freebsd-hackers@freebsd.org mailing list
> http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
> To unsubscribe, send any mail to "freebsd-hackers-unsubscribe@freebsd.org"
> 

--------------030702070506070109040607
Content-Type: text/x-patch;
 name="zfsefi.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="zfsefi.diff"

Index: sys/boot/efi/boot1/Makefile
===================================================================
--- sys/boot/efi/boot1/Makefile	(revision 281381)
+++ sys/boot/efi/boot1/Makefile	(working copy)
@@ -13,7 +13,7 @@
 INTERNALPROG=
 
 # architecture-specific loader code
-SRCS=	boot1.c reloc.c start.S
+SRCS=	boot1.c reloc.c start.S ufs_module.c zfs_module.c
 
 CFLAGS+=	-I.
 CFLAGS+=	-I${.CURDIR}/../include
@@ -20,6 +20,8 @@
 CFLAGS+=	-I${.CURDIR}/../include/${MACHINE_CPUARCH}
 CFLAGS+=	-I${.CURDIR}/../../../contrib/dev/acpica/include
 CFLAGS+=	-I${.CURDIR}/../../..
+CFLAGS+=	-I${.CURDIR}/../../zfs/
+CFLAGS+=	-I${.CURDIR}/../../../cddl/boot/zfs/
 
 # Always add MI sources and REGULAR efi loader bits
 .PATH:		${.CURDIR}/../loader/arch/${MACHINE_CPUARCH}
Index: sys/boot/efi/boot1/boot1.c
===================================================================
--- sys/boot/efi/boot1/boot1.c	(revision 281381)
+++ sys/boot/efi/boot1/boot1.c	(working copy)
@@ -5,6 +5,8 @@
  * All rights reserved.
  * Copyright (c) 2014 Nathan Whitehorn
  * All rights reserved.
+ * Copyright (c) 2014 Eric McCorkle
+ * All rights reverved.
  *
  * 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>
 
@@ -28,6 +29,8 @@
 #include <efi.h>
 #include <eficonsctl.h>
 
+#include "boot_module.h"
+
 #define _PATH_LOADER	"/boot/loader.efi"
 #define _PATH_KERNEL	"/boot/kernel/kernel"
 
@@ -41,14 +44,20 @@
 	u_int	sp_size;
 };
 
+static const boot_module_t* const boot_modules[] =
+{
+#ifdef ZFS_EFI_BOOT
+        &zfs_module,
+#endif
+#ifdef UFS_EFI_BOOT
+        &ufs_module
+#endif
+};
+
+#define NUM_BOOT_MODULES (sizeof(boot_modules) / sizeof(boot_module_t*))
+
 static const char digits[] = "0123456789abcdef";
 
-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 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);
@@ -62,9 +71,67 @@
 static EFI_SYSTEM_TABLE *systab;
 static EFI_HANDLE *image;
 
-static void
-bcopy(const void *src, void *dst, size_t len)
+
+void* Malloc(size_t len, const char* file, int line)
 {
+        void* out;
+        printf("Allocating %lu bytes at %s:%d\n", len, file, line);
+        if (systab->BootServices->AllocatePool(EfiLoaderData,
+                                               len, &out) !=
+            EFI_SUCCESS) {
+                printf("Can't allocate memory pool\n");
+                return NULL;
+        }
+        printf("Allocated pool at %p\n", out);
+        return out;
+}
+
+int strncmp(const char *a, const char *b, size_t len)
+{
+        for (int i = 0; i < len; i++)
+                if(a[i] == '\0' && b[i] == '\0') {
+                        return 0;
+                } else if(a[i] < b[i]) {
+                        return -1;
+                } else if(a[i] > b[i]) {
+                        return 1;
+                }
+
+        return 0;
+}
+
+char* strdup(const char* s) {
+        int len;
+
+        for(len = 1; s[len]; len++);
+
+        char* out = malloc(len);
+
+        for(int i = 0; i < len; i++)
+                out[i] = s[i];
+
+        return out;
+}
+
+int bcmp(const void *a, const void *b, size_t len)
+{
+        const char *sa;
+        const char *sb;
+
+        for (int i = 0; i < len; i++)
+                if(sa[i] != sb[i])
+                        return 1;
+
+        return 0;
+}
+
+int memcmp(const void *a, const void *b, size_t len)
+{
+        return bcmp(a, b, len);
+}
+
+void bcopy(const void *src, void *dst, size_t len)
+{
 	const char *s = src;
 	char *d = dst;
 
@@ -72,23 +139,24 @@
 		*d++ = *s++;
 }
 
-static void
-memcpy(void *dst, const void *src, size_t len)
+void* memcpy(void *dst, const void *src, size_t len)
 {
 	bcopy(src, dst, len);
+        return dst;
 }
 
-static void
-bzero(void *b, size_t len)
+
+void* memset(void *b, int val, size_t len)
 {
 	char *p = b;
 
 	while (len-- != 0)
-		*p++ = 0;
+		*p++ = val;
+
+        return b;
 }
 
-static int
-strcmp(const char *s1, const char *s2)
+int strcmp(const char *s1, const char *s2)
 {
 	for (; *s1 == *s2 && *s1; s1++, s2++)
 		;
@@ -95,30 +163,50 @@
 	return ((u_char)*s1 - (u_char)*s2);
 }
 
+int putchr(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 EFI_GUID BlockIoProtocolGUID = BLOCK_IO_PROTOCOL;
 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;
+#define MAX_DEVS 128
 
-EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
+void efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab)
 {
-	EFI_HANDLE handles[128];
+	EFI_HANDLE handles[MAX_DEVS];
+        dev_info_t module_devs[NUM_BOOT_MODULES][MAX_DEVS];
+        size_t dev_offsets[NUM_BOOT_MODULES];
 	EFI_BLOCK_IO *blkio;
-	UINTN i, nparts = sizeof(handles), cols, rows, max_dim, best_mode;
+	UINTN nparts = sizeof(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;
 
+        // Basic initialization
 	systab = Xsystab;
 	image = Ximage;
 
+        for(int i = 0; i < NUM_BOOT_MODULES; i++)
+        {
+                dev_offsets[i] = 0;
+        }
+
+        // Set up the console, so printf works.
 	BS = systab->BootServices;
 	status = BS->LocateProtocol(&ConsoleControlGUID, NULL,
 	    (VOID **)&ConsoleControl);
@@ -128,10 +216,14 @@
 	/*
 	 * Reset the console and find the best text mode.
 	 */
+        UINTN max_dim;
+        UINTN best_mode;
+        UINTN cols;
+        UINTN rows;
 	conout = systab->ConOut;
 	conout->Reset(conout, TRUE);
 	max_dim = best_mode = 0;
-	for (i = 0; ; i++) {
+	for (int i = 0; ; i++) {
 		status = conout->QueryMode(conout, i,
 		    &cols, &rows);
 		if (EFI_ERROR(status))
@@ -141,6 +233,7 @@
 			best_mode = i;
 		}
 	}
+
 	if (max_dim > 0)
 		conout->SetMode(conout, best_mode);
 	conout->EnableCursor(conout, TRUE);
@@ -147,206 +240,93 @@
 	conout->ClearScreen(conout);
 
 	printf("\n"
-	       ">> FreeBSD EFI boot block\n");
-	printf("   Loader path: %s\n", path);
+	       ">> FreeBSD ZFS-enabled EFI boot block\n");
+	printf("   Loader path: %s\n\n", _PATH_LOADER);
 
+	printf("   Initializing modules:");
+        for(int i = 0; i < NUM_BOOT_MODULES; i++)
+        {
+                if (NULL != boot_modules[i])
+                {
+                        printf(" %s", boot_modules[i]->name);
+                        boot_modules[i]->init(image, systab, BS);
+                }
+        }
+        putchr('\n', NULL);
+
+        // Get all the device handles
 	status = systab->BootServices->LocateHandle(ByProtocol,
 	    &BlockIoProtocolGUID, NULL, &nparts, handles);
 	nparts /= sizeof(handles[0]);
+	//printf("   Scanning %lu device handles\n", nparts);
 
-	for (i = 0; i < nparts; i++) {
+        // Scan all partitions, probing with all modules.
+	for (int i = 0; i < nparts; i++) {
+                dev_info_t devinfo;
+
+                // Figure out if we're dealing with an actual partition
 		status = systab->BootServices->HandleProtocol(handles[i],
 		    &DevicePathGUID, (void **)&devpath);
-		if (EFI_ERROR(status))
+		if (EFI_ERROR(status)) {
+                        //printf("        Not a device path protocol\n");
 			continue;
+                }
 
-		while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
+		while (!IsDevicePathEnd(NextDevicePathNode(devpath))) {
+                        //printf("        Advancing to next device\n");
 			devpath = NextDevicePathNode(devpath);
+                }
 
 		status = systab->BootServices->HandleProtocol(handles[i],
 		    &BlockIoProtocolGUID, (void **)&blkio);
-		if (EFI_ERROR(status))
+		if (EFI_ERROR(status)) {
+                        //printf("        Not a block device\n");
 			continue;
+                }
 
-		if (!blkio->Media->LogicalPartition)
+		if (!blkio->Media->LogicalPartition) {
+                        //printf("        Logical partition\n");
 			continue;
+                }
 
-		if (domount(devpath, blkio, 1) >= 0)
-			break;
-	}
+                // Setup devinfo
+                devinfo.dev = blkio;
+                devinfo.devpath = devpath;
+                devinfo.devhandle = handles[i];
 
-	if (i == nparts)
-		panic("No bootable partition found");
-
-	bootdevhandle = handles[i];
-	load(path);
-
-	panic("Load failed");
-
-	return EFI_SUCCESS;
-}
-
-static int
-dskread(void *buf, u_int64_t lba, int nblk)
-{
-	EFI_STATUS status;
-	int size;
-
-	lba = lba / (bootdev->Media->BlockSize / DEV_BSIZE);
-	size = nblk * DEV_BSIZE;
-	status = bootdev->ReadBlocks(bootdev, bootdev->Media->MediaId, lba,
-	    size, buf);
-
-	if (EFI_ERROR(status))
-		return (-1);
-
-	return (0);
-}
-
-#include "ufsread.c"
-
-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;
+                // Run through each module, see if it can load this partition
+                for (int j = 0; j < NUM_BOOT_MODULES; j++ )
+                {
+                        if (NULL != boot_modules[j] &&
+                            boot_modules[j]->probe(devinfo))
+                        {
+                                // If it can, save it to the device list for
+                                // that module
+                                module_devs[j][dev_offsets[j]++] = devinfo;
+                        }
+                }
 	}
-	size = DIP(di_size);
-	n = size - fs_off;
-	return (n);
-}
 
-static struct dmadat __dmadat;
+        // Select a partition to boot.  We do this by trying each
+        // module in order.
+        for (int i = 0; i < NUM_BOOT_MODULES; i++)
+        {
+                if (NULL != boot_modules[i])
+                {
+                        printf("   Trying to load from %lu %s partitions\n",
+                               dev_offsets[i], boot_modules[i]->name);
+                        boot_modules[i]->load(module_devs[i], dev_offsets[i],
+                                              _PATH_LOADER);
+                        printf("   Failed\n");
+                }
+        }
 
-static int
-domount(EFI_DEVICE_PATH *device, EFI_BLOCK_IO *blkio, int quiet)
-{
-
-	dmadat = &__dmadat;
-	bootdev = blkio;
-	bootdevpath = device;
-	if (fsread(0, NULL, 0)) {
-		if (!quiet)
-			printf("domount: can't read superblock\n");
-		return (-1);
-	}
-	if (!quiet)
-		printf("Succesfully mounted UFS filesystem\n");
-	return (0);
+        // If we get here, we're out of luck...
+        panic("No bootable partitions found!");
 }
 
-static void
-load(const char *fname)
+void panic(const char *fmt, ...)
 {
-	ufs_ino_t ino;
-	EFI_STATUS status;
-	EFI_HANDLE loaderhandle;
-	EFI_LOADED_IMAGE *loaded_image;
-	void *buffer;
-	size_t bufsize;
-
-	if ((ino = lookup(fname)) == 0) {
-		printf("File %s not found\n", fname);
-		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 %lx\n", status);
-
-	status = systab->BootServices->HandleProtocol(loaderhandle,
-	    &LoadedImageGUID, (VOID**)&loaded_image);
-	if (EFI_ERROR(status))
-		printf("HandleProtocol failed with error %lx\n", status);
-
-	loaded_image->DeviceHandle = bootdevhandle;
-
-	status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
-	if (EFI_ERROR(status))
-		printf("StartImage failed with error %lx\n", status);
-}
-
-static void
-panic(const char *fmt, ...)
-{
 	char buf[128];
 	va_list ap;
 
@@ -358,50 +338,25 @@
 	while (1) {}
 }
 
-static int
-printf(const char *fmt, ...)
+int printf(const char *fmt, ...)
 {
 	va_list ap;
 	int ret;
 
-	/* Don't annoy the user as we probe for partitions */
-	if (strcmp(fmt,"Not ufs\n") == 0)
-		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)
+void vprintf(const char *fmt, va_list ap)
 {
-	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);
+	__printf(fmt, putchr, 0, ap);
 }
 
-static int
-vprintf(const char *fmt, va_list ap)
+int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
 {
-	int ret;
-
-	ret = __printf(fmt, putchar, 0, ap);
-	return (ret);
-}
-
-static int
-vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
-{
 	struct sp_data sp;
 	int ret;
 
Index: sys/boot/efi/boot1/boot_module.h
===================================================================
--- sys/boot/efi/boot1/boot_module.h	(revision 0)
+++ sys/boot/efi/boot1/boot_module.h	(working copy)
@@ -0,0 +1,57 @@
+#ifndef _BOOT_MODULE_H_
+#define _BOOT_MODULE_H_
+
+#include <stdbool.h>
+
+#include <efi.h>
+#include <efilib.h>
+#include <eficonsctl.h>
+
+#define UFS_EFI_BOOT 1
+#define ZFS_EFI_BOOT 1
+
+// EFI device info
+typedef struct dev_info_t
+{
+      EFI_BLOCK_IO *dev;
+      EFI_DEVICE_PATH *devpath;
+      EFI_HANDLE *devhandle;
+} 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* const name;
+
+        // Initialize the module.
+        void (* const init)(EFI_HANDLE image,
+                            EFI_SYSTEM_TABLE* systab,
+                            EFI_BOOT_SERVICES *bootsrv);
+
+        // Check to see if curr_dev is a device that this module can handle.
+        bool (* const probe)(dev_info_t dev);
+
+        // Select the best out of a set of devices that probe indicated were
+        // loadable, and load it.
+        void (* const load)(const dev_info_t devs[],
+                            size_t ndevs,
+                            const char* loader_path);
+} boot_module_t;
+
+// Standard boot modules
+#ifdef UFS_EFI_BOOT
+extern const boot_module_t ufs_module;
+#endif
+#ifdef ZFS_EFI_BOOT
+extern const boot_module_t zfs_module;
+#endif
+
+// Functions available to modules
+extern int strcmp(const char *s1, const char *s2);
+extern void bcopy(const void *src, void *dst, size_t len);
+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);
+
+#endif

Property changes on: sys/boot/efi/boot1/boot_module.h
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: sys/boot/efi/boot1/ufs_module.c
===================================================================
--- sys/boot/efi/boot1/ufs_module.c	(revision 0)
+++ sys/boot/efi/boot1/ufs_module.c	(working copy)
@@ -0,0 +1,211 @@
+/*-
+ * 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 are freely
+ * permitted provided that the above copyright notice and this
+ * paragraph and the following disclaimer are duplicated in all
+ * such forms.
+ *
+ * This software is provided "AS IS" and without any express or
+ * implied warranties, including, without limitation, the implied
+ * warranties of merchantability and fitness for a particular
+ * purpose.
+ */
+#include <stdarg.h>
+#include <stdbool.h>
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+
+#include <efi.h>
+
+#include "boot_module.h"
+
+static EFI_HANDLE image;
+static EFI_SYSTEM_TABLE* systab;
+static EFI_BOOT_SERVICES *bootsrv;
+static dev_info_t devinfo;
+static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
+
+static int
+dskread(void *buf, u_int64_t lba, int nblk)
+{
+	EFI_STATUS status;
+	int size;
+
+	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 (EFI_ERROR(status))
+		return (-1);
+
+	return (0);
+}
+
+#include "ufsread.c"
+
+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;
+	}
+	size = DIP(di_size);
+	n = size - fs_off;
+	return (n);
+}
+
+static struct dmadat __dmadat;
+
+static bool
+probe(const dev_info_t dev)
+{
+        devinfo = dev;
+	dmadat = &__dmadat;
+	if (fsread(0, NULL, 0)) {
+		return 0;
+	}
+	return 1;
+}
+
+static void
+try_load(const dev_info_t dev,
+         const char* const loader_path)
+{
+	ufs_ino_t ino;
+	EFI_STATUS status;
+	EFI_HANDLE loaderhandle;
+	EFI_LOADED_IMAGE *loaded_image;
+	void *buffer;
+	size_t bufsize;
+
+        devinfo = dev;
+	if ((ino = lookup(loader_path)) == 0) {
+		printf("File %s not found\n", loader_path);
+		return;
+	}
+
+	bufsize = fsstat(ino);
+	status = systab->BootServices->AllocatePool(EfiLoaderData,
+	    bufsize, &buffer);
+	fsread(ino, buffer, bufsize);
+
+	status = systab->BootServices->LoadImage(TRUE, image, devinfo.devpath,
+	    buffer, bufsize, &loaderhandle);
+
+	status = systab->BootServices->HandleProtocol(loaderhandle,
+	    &LoadedImageGUID, (VOID**)&loaded_image);
+	loaded_image->DeviceHandle = devinfo.devhandle;
+
+	status = systab->BootServices->StartImage(loaderhandle, NULL, NULL);
+}
+
+static void
+load(const dev_info_t devs[],
+     const size_t ndevs,
+     const char* const loader_path)
+{
+        for(int i = 0; i < ndevs; i++)
+        {
+                try_load(devs[i], loader_path);
+        }
+}
+
+
+static void init(EFI_HANDLE xImage,
+                 EFI_SYSTEM_TABLE* xSystab,
+                 EFI_BOOT_SERVICES * xBootsrv)
+{
+        image = xImage;
+        systab = xSystab;
+        bootsrv = xBootsrv;
+}
+
+const boot_module_t ufs_module =
+{
+        .name = "UFS",
+        .init = init,
+        .probe = probe,
+        .load = load
+};

Property changes on: sys/boot/efi/boot1/ufs_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Index: sys/boot/efi/boot1/zfs_module.c
===================================================================
--- sys/boot/efi/boot1/zfs_module.c	(revision 0)
+++ sys/boot/efi/boot1/zfs_module.c	(working copy)
@@ -0,0 +1,237 @@
+/* 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.
+ *
+ * 3. Neither the name of the author nor the names of any contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
+ */
+#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"
+
+#define PATH_CONFIG "/boot/config"
+#define PATH_DOTCONFIG "/boot/.config"
+
+static EFI_HANDLE image;
+static EFI_SYSTEM_TABLE* systab;
+static EFI_BOOT_SERVICES *bootsrv;
+static EFI_GUID LoadedImageGUID = LOADED_IMAGE_PROTOCOL;
+
+static int
+vdev_read(vdev_t * const vdev,
+          void * const priv,
+          const off_t off,
+          void * const buf,
+          const size_t bytes)
+{
+        const dev_info_t* const devinfo = (const dev_info_t*) priv;
+        const off_t lba = off / devinfo->dev->Media->BlockSize;
+        printf("         Request to read %lu bytes at offset %lu, lba %lu to %p\n",
+               bytes, off, lba, buf);
+	const EFI_STATUS status =
+          devinfo->dev->ReadBlocks(devinfo->dev,
+                                   devinfo->dev->Media->MediaId,
+                                   lba, bytes, buf);
+        printf("         Read completed, status %lu\n", status);
+	if (EFI_ERROR(status))
+		return (-1);
+
+	return (0);
+}
+
+static bool probe(dev_info_t dev)
+{
+	printf("     Probing device for ZFS filesystem\n");
+        int result = vdev_probe(vdev_read, &dev, NULL);
+
+        if (result) {
+                printf("     ZFS probe failed\n");
+        }
+
+        return result == 0;
+}
+
+static void try_load(const dev_info_t devinfo,
+                     const char* const loader_path)
+{
+        spa_t *spa;
+        struct zfsmount zfsmount;
+        dnode_phys_t dn;
+        bool autoboot = true;
+
+	printf("     Attempting ZFS mount...");
+        // First, try mounting the ZFS volume
+        if (zfs_spa_init(spa) != 0 || zfs_mount(spa, 0, &zfsmount) != 0) {
+                printf("failed\n");
+                // Mount failed.  Don't report this loudly
+                return;
+        }
+	printf("success\n");
+
+        //vdev_t * const primary_vdev = spa_get_primary_vdev(spa);
+
+	printf("     Attempting lookup of %s...", loader_path);
+        if (zfs_lookup(&zfsmount, loader_path, &dn) == 0) {
+                printf("failed\n");
+                return;
+        }
+	printf("success\n");
+
+	printf("     Attempting to stat...");
+        struct stat st;
+        if (zfs_dnode_stat(spa, &dn, &st)) {
+                printf("Unable to get file statistics\n");
+                return;
+        }
+	printf("success\n");
+
+        const size_t bufsize = st.st_size;
+        void* buffer;
+        EFI_STATUS status;
+        EFI_HANDLE loaderhandle;
+        EFI_LOADED_IMAGE *loaded_image;
+
+	printf("     Attempting to allocate pool of %zu bytes...", bufsize);
+        if (systab->BootServices->AllocatePool(EfiLoaderData,
+                                               bufsize, &buffer) !=
+            EFI_SUCCESS) {
+                printf("Can't allocate loader pool\n");
+                return;
+        }
+	printf("success\n");
+
+	printf("     Attempting to read %zu bytes...", bufsize);
+        if (dnode_read(spa, &dn, 0, buffer, bufsize) < 0) {
+                printf("Can't read image\n");
+                return;
+        }
+	printf("success\n");
+
+	printf("     Attempting to load image...");
+        if (systab->BootServices->LoadImage(TRUE, image, devinfo.devpath,
+                                            buffer, bufsize, &loaderhandle) !=
+            EFI_SUCCESS) {
+                printf("Bad loader image\n");
+                return;
+        }
+	printf("success\n");
+
+	printf("     Attempting to prepare image for execution...");
+        if (systab->BootServices->HandleProtocol(loaderhandle,
+                                                 &LoadedImageGUID,
+                                                 (VOID**)&loaded_image) !=
+            EFI_SUCCESS) {
+                printf("Failed to prepare loader\n");
+                return;
+        }
+	printf("success\n");
+
+        loaded_image->DeviceHandle = devinfo.devhandle;
+
+	printf("     Attempting to execute next stage...");
+        // XXX Set up command args first
+        if (systab->BootServices->StartImage(loaderhandle, NULL, NULL) !=
+            EFI_SUCCESS) {
+                printf("Failed to execute loader\n");
+                return;
+        }
+
+}
+
+static int zfs_mount_ds(const char * const dsname,
+                        struct zfsmount * const zfsmount,
+                        spa_t ** const spa)
+{
+        uint64_t newroot;
+        spa_t *newspa;
+        char *q;
+
+        q = strchr(dsname, '/');
+        if (q)
+	        *q++ = '\0';
+        newspa = spa_find_by_name(dsname);
+        if (newspa == NULL) {
+	        printf("\nCan't find ZFS pool %s\n", dsname);
+	        return -1;
+        }
+
+        if (zfs_spa_init(newspa))
+                return -1;
+
+        newroot = 0;
+        if (q) {
+                if (zfs_lookup_dataset(newspa, q, &newroot)) {
+                        printf("\nCan't find dataset %s in ZFS pool %s\n",
+                               q, newspa->spa_name);
+                        return -1;
+                }
+        }
+        if (zfs_mount(newspa, newroot, zfsmount)) {
+                printf("\nCan't mount ZFS dataset\n");
+                return -1;
+        }
+        *spa = newspa;
+        return (0);
+}
+
+static void load(const dev_info_t devs[],
+                 const size_t ndevs,
+                 const char* const loader_path)
+{
+        for(int i = 0; i < ndevs; i++) {
+                try_load(devs[i], loader_path);
+        }
+}
+
+static void init(EFI_HANDLE xImage,
+                 EFI_SYSTEM_TABLE* xSystab,
+                 EFI_BOOT_SERVICES * xBootsrv)
+{
+        image = xImage;
+        systab = xSystab;
+        bootsrv = xBootsrv;
+        zfs_init();
+}
+
+const boot_module_t zfs_module =
+{
+        .name = "ZFS",
+        .init = init,
+        .probe = probe,
+        .load = load
+};

Property changes on: sys/boot/efi/boot1/zfs_module.c
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:keywords
## -0,0 +1 ##
+FreeBSD=%H
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property

--------------030702070506070109040607--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?55311DA7.8080209>