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

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

I've gotten the ZFS loader to the point where it successfully loads and
attempts to execute the next stage.

I wouldn't say boot1 is in its final state; there's going to have to be
some way to get information about zfs from boot1 to loader, but I
suspect that will fall into place when I'm working on loader itself.

Please try this out on both UFS and ZFS systems, and verify that it does
in fact successfully get all the way through the loading process.

There's also a couple of issues I want to fix before the end:

1) The Malloc implementation uses the EFI memory pool allocator.  This
may not be the best way to go.

2) The module interface probably ought to expose a function that tries
to load a file, returning its contents, rather than trying to load and
execute a file.  This would better support new filesystems, as well as
things like checking cryptographic signatures.

On 04/17/2015 10:50 AM, Eric McCorkle wrote:
> 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"
>>
>>
>>
>> _______________________________________________
>> 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"

--------------020308030103090406010705
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,80 @@
 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;
+        if (systab->BootServices->AllocatePool(EfiLoaderData,
+                                               len, &out) !=
+            EFI_SUCCESS) {
+                printf("Can't allocate memory pool\n");
+                return NULL;
+        }
+        return out;
+}
+
+char* strcpy(char* dst, const char* src) {
+        for(int i = 0; src[i]; i++)
+                dst[i] = src[i];
+
+        return dst;
+}
+
+char* strchr(const char* s, int c) {
+        for(int i = 0; s[i]; i++)
+                if (s[i] == c)
+                        return (char*)(s + i);
+
+        return NULL;
+}
+
+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 = a;
+        const char *sb = b;
+
+        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 +152,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 +176,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 +229,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 +246,7 @@
 			best_mode = i;
 		}
 	}
+
 	if (max_dim > 0)
 		conout->SetMode(conout, best_mode);
 	conout->EnableCursor(conout, TRUE);
@@ -147,206 +253,94 @@
 	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];
+                devinfo.devdata = NULL;
 
-	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 +352,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,58 @@
+#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;
+      void *devdata;
+} 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,210 @@
+/*-
+ * 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) {
+			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(dev_info_t* const 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,215 @@
+/* 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;
+	const EFI_STATUS status =
+          devinfo->dev->ReadBlocks(devinfo->dev,
+                                   devinfo->dev->Media->MediaId,
+                                   lba, bytes, buf);
+	if (EFI_ERROR(status))
+		return (-1);
+
+	return (0);
+}
+
+static bool probe(dev_info_t* const dev)
+{
+        spa_t* spa;
+        int result = vdev_probe(vdev_read, dev, &spa);
+        dev->devdata = spa;
+
+        return result == 0;
+}
+
+static void try_load(const dev_info_t devinfo,
+                     const char* const loader_path)
+{
+        spa_t *spa = devinfo.devdata;
+        struct zfsmount zfsmount;
+        dnode_phys_t dn;
+        bool autoboot = true;
+
+        if (zfs_spa_init(spa) != 0) {
+                // Mount failed.  Don't report this loudly
+                return;
+        }
+
+        // First, try mounting the ZFS volume
+        if (zfs_mount(spa, 0, &zfsmount) != 0) {
+                // Mount failed.  Don't report this loudly
+                return;
+        }
+
+        //vdev_t * const primary_vdev = spa_get_primary_vdev(spa);
+
+        if (zfs_lookup(&zfsmount, loader_path, &dn) != 0) {
+                return;
+        }
+
+        struct stat st;
+        if (zfs_dnode_stat(spa, &dn, &st)) {
+                return;
+        }
+
+        const size_t bufsize = st.st_size;
+        void* buffer;
+        EFI_STATUS status;
+        EFI_HANDLE loaderhandle;
+        EFI_LOADED_IMAGE *loaded_image;
+
+        if (systab->BootServices->AllocatePool(EfiLoaderData,
+                                               bufsize, &buffer) !=
+            EFI_SUCCESS) {
+                return;
+        }
+
+        if (dnode_read(spa, &dn, 0, buffer, bufsize) < 0) {
+                return;
+        }
+
+        if (systab->BootServices->LoadImage(TRUE, image, devinfo.devpath,
+                                            buffer, bufsize, &loaderhandle) !=
+            EFI_SUCCESS) {
+                return;
+        }
+
+        if (systab->BootServices->HandleProtocol(loaderhandle,
+                                                 &LoadedImageGUID,
+                                                 (VOID**)&loaded_image) !=
+            EFI_SUCCESS) {
+                return;
+        }
+
+        loaded_image->DeviceHandle = devinfo.devhandle;
+
+	printf("Image loader, attempting to execute\n");
+        // 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

--------------020308030103090406010705--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?5533A48A.7080708>